package com.bgds.sys.module.serviceimpl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bgds.sys.common.constant.BizConstant;
import com.bgds.sys.common.pagevo.PageVo;
import com.bgds.sys.common.utils.DateUtils;
import com.bgds.sys.module.entity.AlarmLog;
import com.bgds.sys.module.entity.DeviceDynamicAttr;
import com.bgds.sys.module.entity.dto.AlarmDeviceDto;
import com.bgds.sys.module.entity.dto.AlarmInfo;
import com.bgds.sys.module.entity.dto.AlarmLogDto;
import com.bgds.sys.module.mapper.AlarmLogMapper;
import com.bgds.sys.module.service.IAlarmLogService;
import com.bgds.sys.module.service.IDeviceDynamicAttrService;
import com.bgds.sys.module.service.IDeviceService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @author lj
 * 报警日志ServiceImpl
 */
@Service
@Slf4j
public class IAlarmLogServiceImpl extends ServiceImpl<AlarmLogMapper, AlarmLog> implements IAlarmLogService {
    @Autowired
    private AlarmLogMapper alarmLogMapper;
    @Autowired
    private IDeviceService iDeviceService;
    @Resource
    private IDeviceDynamicAttrService iDeviceDynamicAttrService;

    /**
     * 时间段分页模糊查询报警日志
     *
     * @param startTime 起始时间
     * @param endTime   结束时间
     * @param status    状态
     * @param pageVo
     * @return
     */
    @Override
    public IPage<AlarmLogDto> queryForPage(Long startTime, Long endTime, Integer status, String deviceName, String attrName, Integer alarmLevel, PageVo pageVo) {
        IPage<AlarmLogDto> page = new Page<>(pageVo.getPageNumber(), pageVo.getPageSize());

        return alarmLogMapper.queryForPage(page, startTime, endTime, status, deviceName, attrName, alarmLevel);
    }

    /**
     * 时间段分页查询报警日志
     *
     * @param startTime 起始时间
     * @param endTime   结束时间
     * @param status    状态
     * @param pageVo
     * @return
     */
    @Override
    public IPage<AlarmLogDto> listByParam(Long startTime, Long endTime, Integer status, PageVo pageVo) {

        IPage<AlarmLogDto> page = new Page<>(pageVo.getPageNumber(), pageVo.getPageSize());

        return alarmLogMapper.listByPage(page, startTime, endTime, status);

    }

    /**
     * 时间段查询报警日志
     *
     * @param startTime 起始时间
     * @param endTime   结束时间
     * @return
     */
    @Override
    public List<AlarmLogDto> listByParam(String deviceCode, Long startTime, Long endTime) {
        List<AlarmLogDto> alarmLogs = alarmLogMapper.listByParam(deviceCode, startTime, endTime);
        return alarmLogs;

    }

    /**
     * 过去两个小时报警次数
     *
     * @param startTime 起始时间
     * @param endTime   结束时间
     * @return
     */
    @Override
    public Integer count2Hour(String startTime, String endTime) {
        List<AlarmLogDto> alarmLogs = alarmLogMapper.listByParam(null, DateUtils.getBeforeTimeInMillis(2), System.currentTimeMillis());
        Map<Long, List<AlarmLogDto>> groupMap = alarmLogs.stream().
                collect(
                        Collectors.groupingBy((AlarmLogDto wl) -> wl.getAttrId())
                );

        List<AlarmLogDto> alarmLogList = new ArrayList<>();

        groupMap.forEach((k, v) -> {

            for (int i = 0; i < v.size() - 1; ++i) {
                long timeOne = v.get(i).getAlarmDate();
                long timeTwo = v.get(i + 1).getAlarmDate();
                long diff = timeOne - timeTwo;
                if (diff < 60000) {
                    alarmLogList.add(v.get(i + 1));
                }
            }
        });
        return alarmLogs.size() - alarmLogList.size();
    }

    /**
     * 获取最近两个小时报警信息
     *
     * @return
     */
    @Override
    public IPage<AlarmLogDto> nearest2HourAlarmLog(Integer pageNum, Integer pageSize) {
        IPage<AlarmLogDto> iPage = new Page<>(pageNum, pageSize);
        IPage<AlarmLogDto> alarmLogs = alarmLogMapper.listByPage(iPage, DateUtils.getBeforeTimeInMillis(2), System.currentTimeMillis(), null);
        return alarmLogs;

    }

    /**
     * 获取最近两个小时报警设备
     *
     * @return
     */
    @Override
    public List<AlarmDeviceDto> nearest2HourAlarmDevices() {
        List<AlarmLogDto> alarmLogDtos = alarmLogMapper.listByParam(null, DateUtils.getBeforeTimeInMillis(2), System.currentTimeMillis());
        //List<AlarmLogDto> alarmLogDtos = alarmLogMapper.listByParam(null,null,System.currentTimeMillis());
        //报警点分组
        Map<String, List<AlarmLogDto>> groupMap = alarmLogDtos.stream().
                collect(
                        Collectors.groupingBy(log -> log.getDeviceCode())
                );
        //取每个报警点最近报警记录
        List<AlarmLogDto> logDtos = new ArrayList<>();
        groupMap.forEach((k, v) -> {
            AlarmLogDto alarmLogDto = v.stream().max(Comparator.comparing(AlarmLogDto::getAlarmDate)).get();
            logDtos.add(alarmLogDto);
        });
        //报警设备
        List<AlarmDeviceDto> deviceDtos = new ArrayList<>();
        for (AlarmLogDto alarmLogDto : logDtos) {
            AlarmDeviceDto alarmDeviceDto = new AlarmDeviceDto(
                    alarmLogDto.getId(),
                    alarmLogDto.getRegionName(),
                    alarmLogDto.getDeviceCode(),
                    alarmLogDto.getDeviceName(),
                    alarmLogDto.getAlarmDate()
            );
            deviceDtos.add(alarmDeviceDto);
        }
        if (deviceDtos.size() > 0 && deviceDtos != null && deviceDtos.size() >= 10) {
            return deviceDtos.stream().sorted(Comparator.comparing(AlarmDeviceDto::getAlarmTime).reversed()).collect(Collectors.toList()).subList(0, 10);
        }
        return deviceDtos;

    }

    @Override
    public AlarmInfo getMaxAlarmTime() {
        return alarmLogMapper.getByMaxTime();
    }


    /**
     * 取出最近2小时内未处理的报警日志
     */
    @Override
    public List<AlarmLog> unhandleLog() {
        QueryWrapper<AlarmLog> wrapper = new QueryWrapper<>();
        wrapper.eq("status", 0);
        wrapper.gt("alarm_date", System.currentTimeMillis() - BizConstant.TWO_HOUR_MILLIS);
        List<AlarmLog> alarmLogs = alarmLogMapper.selectList(wrapper);
        return alarmLogs;
    }

    @Override
    //@Transactional(rollbackFor = Exception.class)
    public void saveAlarmLogs(Map<String, List<AlarmLog>> alarmLogsMap) {
        if (CollectionUtil.isEmpty(alarmLogsMap)) {
            return;
        }

        List<AlarmLog> alarmLogList = alarmLogsMap.get(BizConstant.ALARM);
        if (CollectionUtil.isEmpty(alarmLogList)) {
          //  log.info("不存在报警设备");
            handleNotAlarmLogs(alarmLogsMap.get(BizConstant.NOT_ALARM));
            return;
        }
        //log.info("报警设备attrId:{}", alarmLogList.stream().map(AlarmLog::getAttrId).collect(Collectors.toList()));

        List<Long> alarmAttrIds = alarmLogList.stream().map(AlarmLog::getAttrId).distinct().collect(Collectors.toList());
        //查询设备动态属性表
        LambdaQueryWrapper<DeviceDynamicAttr> attrQw = Wrappers.lambdaQuery();
        attrQw.in(DeviceDynamicAttr::getId, alarmAttrIds).select(DeviceDynamicAttr::getId, DeviceDynamicAttr::getAlarmStatus);
        List<DeviceDynamicAttr> dynamicAttrs = iDeviceDynamicAttrService.list(attrQw);
        Map<Long, Integer> attrAndAlarmStatusMap = dynamicAttrs.stream().collect(Collectors.toMap(DeviceDynamicAttr::getId, DeviceDynamicAttr::getAlarmStatus, (key1, key2) -> key2));


        //报警规则
        alarmLogList.forEach(alarmLog -> {
            Long attrId = alarmLog.getAttrId();
            //查询出未处理的报警日志列表
            LambdaQueryWrapper<AlarmLog> qw = Wrappers.lambdaQuery();
            qw.eq(AlarmLog::getStatus, 0).in(AlarmLog::getAttrId, attrId).orderByDesc(AlarmLog::getCreateTime).last(" limit 1");
            List<AlarmLog> alarmList = alarmLogMapper.selectList(qw);

            if (BizConstant.ZERO.equals( attrAndAlarmStatusMap.get(attrId))) {
                //如果报警日志表存在则增加报警次数,否则新增记录（不设置id就行了）
                if (CollectionUtil.isNotEmpty(alarmList)) {
                    alarmLog.setId(alarmList.get(0).getId());
                    alarmLog.setAlarmCount((alarmList.get(0).getAlarmCount())+1);
                }
            }
            if (BizConstant.ONE.equals( attrAndAlarmStatusMap.get(attrId))) {
                if (CollectionUtil.isNotEmpty(alarmList)) {
                    alarmLog.setId(alarmList.get(0).getId());
                }
            }
        });


        //更新设备动态属性表报警状态为1
        UpdateWrapper<DeviceDynamicAttr> uw = new UpdateWrapper<>();
        uw.lambda().in(DeviceDynamicAttr::getId, alarmAttrIds).set(DeviceDynamicAttr::getAlarmStatus, BizConstant.ONE);
        iDeviceDynamicAttrService.update(uw);
        //处理非报警Log,把设备动态属性报警状态改为正常0
        handleNotAlarmLogs(alarmLogsMap.get(BizConstant.NOT_ALARM));
        //更新报警日志表
        this.saveOrUpdateBatch(alarmLogList);
    }


    @Override
    public void handleNotAlarmLogs(List<AlarmLog> notAlarmLog) {
        if (CollectionUtil.isEmpty(notAlarmLog)) {
            log.info("非报警设备动态属性为空");
            return;
        }
        log.info("非报警设备attrId:{}", notAlarmLog.stream().map(AlarmLog::getAttrId).collect(Collectors.toList()));
        List<Long> notAlarmAttrIds = notAlarmLog.stream().map(AlarmLog::getAttrId).distinct().collect(Collectors.toList());
        //更新设备动态属性表报警状态为0
        UpdateWrapper<DeviceDynamicAttr> uw = new UpdateWrapper<>();
        uw.lambda().in(DeviceDynamicAttr::getId, notAlarmAttrIds).set(DeviceDynamicAttr::getAlarmStatus, BizConstant.ZERO);
        iDeviceDynamicAttrService.update(uw);
    }


    @Override
    public List<AlarmLog> listByDeviceCode(String deviceCode) {
        return alarmLogMapper.listByDeviceCode(deviceCode);
    }

    @Override
    public Integer decideDeviceLevel(String deviceCode) {
        //通过日志判断是否异常
        List<AlarmLog> alarmLogs = listByDeviceCode(deviceCode);
        if (CollectionUtil.isNotEmpty(alarmLogs)) {
            //获取最大报警等级的日志
            Optional<AlarmLog> max = alarmLogs.stream().max(Comparator.comparingLong(AlarmLog::getAlarmLevel));
            AlarmLog maxLog = max.get();
            if (maxLog.getAlarmLevel().equals(1) || maxLog.getAlarmLevel() == 2) {
                return 1;
            } else {
                return 2;
            }
        } else {
            return 0;
        }
    }

    @Override
    public List<AlarmLog> findByAttrId(Long attrId) {
        QueryWrapper<AlarmLog> qw = new QueryWrapper<>();
        qw.lambda().eq(AlarmLog::getAttrId, attrId).eq(AlarmLog::getStatus, 0);
        List<AlarmLog> logs = alarmLogMapper.selectList(qw);
        return logs;
    }

    @Override
    public List<AlarmLog> findBatchByAttrIds(List<Long> attrIds) {
        return alarmLogMapper.listByAttrIds(attrIds);
    }


}
